package com.sojson.util.encrypt.bothway.imparity.sm2.impl.sign;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.SM2Signer;

import com.sojson.util.StringUtil;
import com.sojson.util.encrypt.bothway.imparity.sm2.IKeyPairGenerator;
import com.sojson.util.encrypt.bothway.imparity.sm2.ISm2SignUtil;
import com.sojson.util.encrypt.bothway.imparity.sm2.Sm2Util;

/**
 * Sms2双向非对称加解密工具类
 * 
 * @author liu
 * @date 2020-09-04
 */
public class Sm2SignUtilImpl implements ISm2SignUtil, IKeyPairGenerator {

    private static Sm2SignUtilImpl instances;

    /**
    * 签名
    * @param data 数据
    * @return 签名
    */
    @Override
    public String sign(String data, String privateKey) throws Exception {
        return signToStr(data.getBytes(), privateKey);
    }

    /**
    * 签名
    * @param data 数据
    * @return 签名
    */
    @Override
    public byte[] signToByte(String data, String privateKey) throws Exception {
        return sign(data.getBytes(), privateKey);
    }

    /**
    * 签名
    * @param data 数据
    * @return 签名
    */
    @Override
    public String signToStr(byte[] data, String privateKey) throws Exception {
        return Sm2Util.encryptContentToStr(signInit(data, privateKey));
    }

    /**
    * 签名
    * @param data 数据
    * @return 签名
    */
    @Override
    public byte[] sign(byte[] data, String privateKey) throws Exception {
        return signToStr(data, privateKey).getBytes();
    }

    /**
    * 签名
    * @param data 数据
    * @return 签名
    */
    private byte[] signInit(byte[] data, String privateKey) throws Exception {
        SM2Signer signer = new SM2Signer();
        CipherParameters param = new ParametersWithRandom(privateKeyToParams(ALGORITHM, privateKey));
        signer.init(true, param);
        signer.update(data, 0, data.length);
        return signer.generateSignature();
    }

    /**
     * 用公钥检验数字签名的合法性
     * @param data      数据
     * @param sign      签名
     * @param publicKey 公钥
     * @return 是否验证通过
     */
    @Override
    public boolean verify(String data, String sign, String publicKey) throws Exception {
        return verifyInit(data.getBytes(), Sm2Util.decryptContentToByte(sign), publicKey);
    }

    /**
     * 用公钥检验数字签名的合法性
     * @param data      数据
     * @param sign      签名
     * @param publicKey 公钥
     * @return 是否验证通过
     */
    @Override
    public boolean verify(byte[] data, byte[] sign, String publicKey) throws Exception {
        return verify(new String(data), new String(sign), publicKey);
    }

    /**
     * 用公钥检验数字签名的合法性
     * @param data      数据
     * @param sign      签名
     * @param publicKey 公钥
     * @return 是否验证通过
     */
    private boolean verifyInit(byte[] data, byte[] sign, String publicKey) throws Exception {
        SM2Signer signer = new SM2Signer();
        CipherParameters param = publicKeyToParams(ALGORITHM, publicKey);
        signer.init(false, param);
        signer.update(data, 0, data.length);
        return signer.verifySignature(sign);
    }

    /**
     * 判断一个对象是否是空(空对象)
     * 
     * @param obj
     * @return
     */
    private static boolean isBlankObject(Object obj) {
        return StringUtil.isBlankObject(obj);
    }

    public static Sm2SignUtilImpl getInstances() {
        if (isBlankObject(instances)) {
            instances = new Sm2SignUtilImpl();
        }
        return instances;
    }

}